package XunChunCPU.EXE

// 算术逻辑运算单元
import chisel3._ 
import chisel3.util._
import XunChunCPU.common.CommonConfig._ 
import XunChunCPU.common.Bundles._
import java.nio.channels.UnresolvedAddressException
class ALU extends Module {
    val io = IO(new Bundle{
        val ready_out = Output(Bool())
        val valid_out = Output(Bool())
        val exeInfo = Flipped(new ExeInfo)
        val memInfo = new MemInfo
        val wbInfo = new WBInfo
        val bypassFromExe = new ByPassBundle
        val bypassFromMem2 = Flipped(new ByPassBundle)          // 从MEM阶段来的旁路
        // 去ID阶段的旁路2，用于判断LB和LW之后的Branch指令跳转
        val isLBandLW = Output(Bool())
        val wregAddr = Output(UInt(5.W))
        // 
        val stallFromEXE = Output(Bool())
        // 访存信号
        val addr = Output(UInt(instrAddrLen.W))
        val wr = Output(Bool())
        val size = Output(UInt(2.W))
        val wdata = Output(UInt(32.W))
        // MUL加速器
        val OpA = Output(UInt(32.W))
        val OpB = Output(UInt(32.W))
        val mulans = Input(UInt(32.W))
    })
    val signOperA = Wire(UInt(33.W))
    val signOperB = Wire(UInt(33.W))
    val wdatatmp = Wire(UInt(32.W))
    val addAns = Wire(UInt(33.W))       // 加法结果
    val subAns = Wire(UInt(33.W))       // 减法结果
    //val mulAns = Wire(SInt(64.W))       // 乘法结果
    val exception = Wire(UInt(2.W))     // 例外
    // 算术运算
    val trueA = Wire(UInt(32.W))
    val trueB = Wire(UInt(32.W))
    // 更新A或者B
    when(io.bypassFromMem2.regAddr =/= 0.U && io.exeInfo.AFromReg === true.B && io.exeInfo.ARegAddr === io.bypassFromMem2.regAddr){
        trueA := io.bypassFromMem2.regData
    }.otherwise{
        trueA := io.exeInfo.OperA
    }
    when(io.bypassFromMem2.regAddr =/= 0.U && io.exeInfo.BFromReg === true.B && io.exeInfo.BRegAddr === io.bypassFromMem2.regAddr){
        trueB := io.bypassFromMem2.regData
    }.otherwise{
        trueB := io.exeInfo.OperB
    }
    signOperA := Cat(trueA(31),trueA)
    signOperB := Cat(trueB(31),trueB)
    addAns := signOperA + signOperB
    subAns := signOperA - signOperB
    //mulAns := trueA.asSInt() * trueB.asSInt()

    io.OpA := trueA
    io.OpB := trueB

    io.wbInfo.regAddr := io.exeInfo.wAddr
    io.wbInfo.regwe := io.exeInfo.regwe
    // exception & wdata
    when(io.exeInfo.op === OP_ADD){
        when(addAns(32) =/= addAns(31)) {
            exception := IntegerOverflow
            wdatatmp := addAns(31,0)
        }.otherwise{
            exception := NoException
            wdatatmp := addAns(31,0)
        }
    }.elsewhen(io.exeInfo.op === OP_ADDU){
        exception := NoException
        wdatatmp := addAns(31,0)
    }.elsewhen(io.exeInfo.op === OP_SUB){
        when(subAns(32) =/= subAns(31)) {
            exception := IntegerOverflow
            wdatatmp := subAns(31,0)
        }.otherwise{
            exception := NoException
            wdatatmp := subAns(31,0)
        }
    }.elsewhen(io.exeInfo.op === OP_SLT){
        exception := NoException
        when(trueA.asSInt() < trueB.asSInt()){
            wdatatmp := 1.U
        }.otherwise{
            wdatatmp := 0.U
        }
    }.elsewhen(io.exeInfo.op === OP_MUL){
        exception := NoException
        //wdatatmp := mulAns(31,0)
        wdatatmp := io.mulans
    }.elsewhen(io.exeInfo.op === OP_AND){
        exception := NoException
        wdatatmp := trueA & trueB
    }.elsewhen(io.exeInfo.op === OP_LUI){
        exception := NoException
        wdatatmp := Cat(trueB(15,0),0.U(16.W))
    }.elsewhen(io.exeInfo.op === OP_OR){
        exception := NoException
        wdatatmp := trueA | trueB
    }.elsewhen(io.exeInfo.op === OP_XOR){
        exception := NoException
        wdatatmp := trueA ^ trueB
    }.elsewhen(io.exeInfo.op === OP_SLL){
        exception := NoException
        wdatatmp := trueB << trueA(5,0)
    }.elsewhen(io.exeInfo.op === OP_SRA){
        exception := NoException
        wdatatmp := (trueB.asSInt() >> trueA(5,0)).asUInt()
    }.elsewhen(io.exeInfo.op === OP_SRL){
        exception := NoException
        wdatatmp := trueB >> trueA(5,0)
    }.elsewhen(io.exeInfo.op === OP_JAL || io.exeInfo.op === OP_JALR){
        exception := NoException
        wdatatmp := trueA
    }.otherwise{
        when(io.exeInfo.op === OP_LW && trueA(1,0) =/= 0.U){
            exception := AddressError
        }.elsewhen(io.exeInfo.op === OP_SW && trueA(1,0) =/= 0.U){
            exception := AddressError
        }.otherwise{
            exception := NoException
        }
        wdatatmp := 0.U
    }
    io.wbInfo.wData := wdatatmp
    // bypass
    io.bypassFromExe.regData := wdatatmp
    when(io.exeInfo.regwe === true.B && io.exeInfo.op =/= OP_LB && io.exeInfo.op =/= OP_LW){
        io.bypassFromExe.regAddr := io.exeInfo.wAddr
    }.otherwise{
        io.bypassFromExe.regAddr := 0.U
    }
    // memAddr
    io.memInfo.memAddr := trueA

    // memType 和访存信号
    when(io.exeInfo.op === OP_LB){
        io.memInfo.memType := MemLB
        io.wr := false.B
        io.addr := io.exeInfo.OperA
        io.size := 0.U
        io.wdata := 0.U
    }.elsewhen(io.exeInfo.op === OP_LW){
        io.wr := false.B
        io.addr := io.exeInfo.OperA
        io.size := 2.U
        io.wdata := 0.U
        when(trueA(1,0) =/= 0.U){
            io.memInfo.memType := MemNothing
        }.otherwise{
            io.memInfo.memType := MemLW
        }
    }.elsewhen(io.exeInfo.op === OP_SB){
        io.wr := true.B
        io.addr := io.exeInfo.OperA
        io.size := 0.U
        io.memInfo.memType := MemSB
        when(io.memInfo.memAddr(1,0) === 0.U){
            io.wdata := io.exeInfo.OperB
        }.elsewhen(io.memInfo.memAddr(1,0) === 1.U){
            io.wdata := Cat(0.U(16.W),io.exeInfo.OperB(7,0),0.U(8.W))
        }.elsewhen(io.memInfo.memAddr(1,0) === 2.U){
            io.wdata := Cat(0.U(8.W),io.exeInfo.OperB(7,0),0.U(16.W))
        }.otherwise{
            io.wdata := Cat(io.exeInfo.OperB(7,0),0.U(24.W))
        }
    }.elsewhen(io.exeInfo.op === OP_SW){
        io.wdata := io.exeInfo.OperB
        io.wr := true.B
        io.addr := io.exeInfo.OperA
        io.size := 2.U
        when(trueA(1,0) =/= 0.U){
            io.memInfo.memType := MemNothing
        }.otherwise{
            io.memInfo.memType := MemSW
        }
    }.otherwise{
        io.wr := false.B
        // 访存阶段默认访问ExtRam
        io.addr := 0x80400000L.U
        io.wdata := 0.U
        io.size := 2.U
        io.memInfo.memType := MemNothing
    }
    // 旁路2
    io.wregAddr := io.exeInfo.wAddr
    when(io.exeInfo.op === OP_LB || io.exeInfo.op === OP_LW){
        io.isLBandLW := true.B
    }.otherwise{
        io.isLBandLW := false.B
    }
    when(io.exeInfo.op === OP_SB || io.exeInfo.op === OP_SW){
        when(io.exeInfo.OperA(22) === 0.U){
            io.stallFromEXE := true.B
        }.otherwise{
            io.stallFromEXE := false.B
        }
    }.otherwise{
        io.stallFromEXE := false.B
    }
    // 如果是MUL进行加速
    val state = RegInit(false.B)
    when(state===false.B){
        when(io.exeInfo.op === OP_MUL){
            state := true.B
        }.otherwise{
            state := false.B
        }
    }.otherwise{
        state := false.B
    }
    when(io.exeInfo.op === OP_MUL && state === false.B){
        io.ready_out := false.B
        io.valid_out := false.B
    }.otherwise{
        io.ready_out := true.B
        io.valid_out := true.B
    }
}